package com.itheima.health.common;


import com.alibaba.fastjson.JSON;
import com.itheima.health.entity.Result;
import com.itheima.health.pojo.Permission;
import com.itheima.health.pojo.Role;
import com.itheima.health.pojo.User;
import com.itheima.health.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


@WebFilter(urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {

    //  需要设置权限列表 以及权限关键字
    private void initAutlUrlMap() {
        // 初始化这里 完成  map初始化
        // 初始化  哪些路径 需要  哪些权限
        //  解释  你如果访问的路径是 检查项的删除  必须要有 CHECKITEM_DELETE 的权限!!
        loginAuthUrlMap.put("/checkitem/delete", "CHECKITEM_DELETE");
        loginAuthUrlMap.put("/checkgroup/delete", "CHECKGROUP_DELETE");
        loginAuthUrlMap.put("/setmeal/delete", "SETMEAL_DELETE");
        loginAuthUrlMap.put("/report/**", "REPORT_VIEW");
    }


    private String[] authUrl = new String[]{//设置无需登录的地址
            "/user/login",
            "/user/logout",
            "/common/**",
            "/mobile/**" //移动端无需登录
    };

    @Autowired
    private UserService userService;

    // 判断需不需要登录才能访问 的资源
    // 判断 登录后  该资源 是否需要进行权限校验后访问
    //   如果 不需要 返回true     如果需要 且权限匹配上了 返回true
    //   如果 不匹配 说明 没有权限
    // 定义登录后  需要授权才能访问的URI 集合
    //  /checkitem/delete   对应一个权限关键字  CHECKITEM_DELETE
    //  /checkgroup/delete  对应一个权限关键字  CHECKGROUP_DELETE
    //  /setmeal/delete                        SETMEAL_DELETE
    //  /report/**                             REPORT_VIEW
    //   定义 存储 uri 权限校验路径  和  权限校验关键字  集合
    //             String           String
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String requestURI = request.getRequestURI();
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        log.info("[权限检查过滤器...],当前uri:{}", requestURI);

        boolean isNotLoginAccess = checkURI(requestURI);
        if (isNotLoginAccess) {//白名单通过
            log.info("白名单放行URI:" + requestURI);
            filterChain.doFilter(request, response);
            return;
        }
// false  需要登录访问   --- 判断是否登录 登录再放行 没登录 提示需要登录访问
        Object user = request.getSession().getAttribute("user");
        if (user != null) {//已经登录了  后台管理员用户登录
            //直接查看该用户  有没有访问该路径的权限
            boolean isLoginAuth = checkLoginAuthURI(requestURI, (User) user);

            if (isLoginAuth) {//有权限 放行
                filterChain.doFilter(request, response);
            } else { //没有权限 提示没权限
                response.setContentType("application/json;charset=utf-8");
                Result result = new Result(false, "无访问权限");
                // 如何把这个对象变成json格式呢?
                String json = JSON.toJSONString(result);
                //把对象转换成 json格式数据
                response.getWriter().write(json);
            }

        } else {
            //未登录
            response.setContentType("application/json;charset=utf-8");
            // 内容 以 json格式 格式解析 遇到中文 用utf-8

            //response.setContentType("text/html;charset=utf-8");
            //内容用 html语法解析,中文 utf-8

            Result result = new Result(false, "请重新登录");
            // 如何把这个对象变成json格式呢?
            String json = JSON.toJSONString(result);
            //把对象转换成 json格式数据
            response.getWriter().write(json);//?
        }


    }

    private boolean checkURI(String reqUri) {
        //  判断一个 这个 reqUri 是不是白名单数据
        //   路径匹配器
        AntPathMatcher pathMatcher = new AntPathMatcher();
        //遍历数组
        // url 白名单规则    reqUri 请求的路径
        for (String url : authUrl) {
            if (pathMatcher.match(url, reqUri)) {
                log.info("[权限过滤器,匹配是白名单:uri:{}]", reqUri);
                return true;
            }
        }
        return false;//需要登录访问
    }


    private boolean checkLoginAuthURI(String reqUri, User user) {
        // 路径匹配器
        AntPathMatcher matcher = new AntPathMatcher();
        // 1: 匹配 reqUri 是不是 在 哪个map集合 匹配规则中
        // 如果不是就 返回true  说明谁都具备访问的权限
        Set<String> keySet = loginAuthUrlMap.keySet();
        //  keySet  具有权限路径规则
        String currKeyUrl = null; //用它来接收 匹配出来的 路径规则
        for (String urlKey : keySet) {
            // 键路径 匹配规则   reqUri匹配
            if (matcher.match(urlKey, reqUri)) {//true 说明 这个路径需要权限访问
                currKeyUrl = urlKey;
            }
        }
        if (currKeyUrl == null) {//说明该路径不需要权限访问  谁都有访问权限
            log.info("当前访问路径,不需要权限校验,谁都有权限...");
            return true;
        }
        //走到这里说明 !=null  该路径需要进行权限校验
        // 取出权限关键字
        String authKeyword = loginAuthUrlMap.get(currKeyUrl);
        log.info("该路径需要权限访问,且访问权限关键字是:" + authKeyword);

        //只要检查用户对象中对应的所有权限关键字   跟  路径权限关键字进行匹配
        //  只要匹配上 说明有访问权限 如果没有匹配上 没有权限
        //查询用户角色
        Set<Role> roles = userService.selectRoles(user.getId());//角色
        //查看 角色 对应哪些权限
        for (Role role : roles) {

            //获取角色 权限
            Set<Permission> permissions = userService.selectPermissions(role.getId());
            // 这个是每一个 权限 实体对象 ---里面的 keyword
            for (Permission permission : permissions) {
                if (permission.getKeyword().equals(authKeyword)) {
                    log.info("当前用户权限匹配上了,允许访问");
                    //具备了权限
                    return true;
                }
            }
        }

        //大循环做完 没有权限
        return false;


    }

    private Map<String, String> loginAuthUrlMap = new HashMap<>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        initAutlUrlMap();
    }

    public void destroy() {
    }


}
